/* ADC1 Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"

// 默认参考电压
#define DEFAULT_VREF 1100 // Use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES 64  // Multisampling

static esp_adc_cal_characteristics_t *adc_chars;
#if CONFIG_IDF_TARGET_ESP32C3
static const adc_channel_t channel = ADC_CHANNEL_1; // GPIO34 if ADC1, GPIO14 if ADC2
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
#elif CONFIG_IDF_TARGET_ESP32S3
static const adc_channel_t channel = ADC_CHANNEL_1; // GPIO7 if ADC1, GPIO17 if ADC2
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
#endif
static const adc_atten_t atten = ADC_ATTEN_DB_11; // ADC衰减参数。不同的参数决定了ADC的范围
static const adc_unit_t unit = ADC_UNIT_1;        // 用于ADC数字控制器(DMA模式)

// 检查电子保险丝管理器
static void check_efuse(void)
{
    // 检查TP是否烧录到eFuse
    if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK)
    {
        printf("eFuse Two Point: Supported\n");
    }
    else
    {
        printf("eFuse Two Point: NOT supported\n");
    }
    // 检查Vref是否烧录到eFuse
    if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK)
    {
        printf("eFuse Vref: Supported\n");
    }
    else
    {
        printf("eFuse Vref: NOT supported\n");
    }
}

//表征中使用的校准值类型
static void print_char_val_type(esp_adc_cal_value_t val_type)
{
    if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP)
    {
        printf("Characterized using Two Point Value\n");
    }
    else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF)
    {
        printf("Characterized using eFuse Vref\n");
    }
    else
    {
        printf("Characterized using Default Vref\n");
    }
}

void app_main(void)
{
    check_efuse();// 检查电子保险丝管理器

    // Configure ADC
    if (unit == ADC_UNIT_1)// 选择ADC单元
    {
        adc1_config_width(width);                  // 设置位宽
        adc1_config_channel_atten(channel, atten); // 设置通道和衰减系数
    }
    else
    {
        adc2_config_channel_atten((adc2_channel_t)channel, atten);
    }

    // Characterize ADC
    adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); // 与malloc不同，calloc可以开拓一块为0的区域
    // 进行adc的初始化
    esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit,         // 描述ADC (ADC_UNIT_1或ADC_UNIT_2)
                                                            atten,        // 衰减特征
                                                            width,        // ADC的位宽配置
                                                            DEFAULT_VREF, // 默认ADC参考电压(mV)
                                                            adc_chars);   // 指向用于存储ADC特征的空结构的指针
    print_char_val_type(val_type);// 表征中使用的校准值类型

    // Continuously sample ADC1
    while (1)
    {
        uint32_t adc_reading = 0;
        // Multisampling
        for (int i = 0; i < NO_OF_SAMPLES; i++)// 采样次数
        {
            if (unit == ADC_UNIT_1)
            {
                adc_reading += adc1_get_raw((adc1_channel_t)channel);// 读取ADC1通道的值
            }
            else
            {
                int raw;
                adc2_get_raw((adc2_channel_t)channel, width, &raw);// 读取ADC2通道的值
                adc_reading += raw;
            }
        }
        adc_reading /= NO_OF_SAMPLES;// 平均值
        //这个函数根据ADC的特征将ADC读数转换为mV电压
        uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);// 将ADC的原始值转换为电压值
        printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);
        vTaskDelay(500/portTICK_PERIOD_MS);
    }
}
